package com.hsgene.user.service.impl;

import com.hsgene.common.util.basic.UUID32;
import com.hsgene.common.util.exception.ErrorCode;
import com.hsgene.common.util.result.ApiResult;
import com.hsgene.common.util.security.MD5Utils;
import com.hsgene.common.util.support.Pagination;
import com.hsgene.user.constants.CustomerSourceType;
import com.hsgene.user.constants.UserIntType;
import com.hsgene.user.converter.UserConverter;
import com.hsgene.user.domain.GeneticTestingOperationAccount;
import com.hsgene.user.domain.GeneticTestingUser;
import com.hsgene.user.dto.login.UserLoginInfoDto;
import com.hsgene.user.dto.login.WeChatBindingRequestDto;
import com.hsgene.user.dto.login.WeChatLoginResponseDto;
import com.hsgene.user.dto.register.RegisterDto;
import com.hsgene.user.dto.user.GeneticTestingUserDto;
import com.hsgene.user.exception.UserErrorCode;
import com.hsgene.user.persistence.GeneticTestingUserRepository;
import com.hsgene.user.persistence.ManagerRepository;
import com.hsgene.user.persistence.OperationAccountRepository;
import com.hsgene.user.persistence.UserRepository;
import com.hsgene.user.service.LoginService;
import com.hsgene.user.service.RegisterService;
import com.hsgene.user.service.SmsService;
import com.hsgene.user.service.api.SecurityService;
import com.hsgene.user.service.api.VersionService;
import com.hsgene.user.support.WeChatLoginSupport;
import com.hsgene.user.support.dto.WeChatSessionResponse;
import com.hsgene.version.dto.VersionDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 用户登录ServiceImpl
 *
 * @author wangbing
 * @version 1.0, 2018/7/2
 */
@Service
public class LoginServiceImpl implements LoginService {

    private final static Logger LOGGER = LoggerFactory.getLogger(LoginServiceImpl.class);

    @Resource
    private UserRepository userRepository;

    @Resource
    private ManagerRepository managerRepository;

    @Resource
    private RegisterService registerService;

    @Resource
    private SmsService smsService;

    @Resource
    private SecurityService securityService;

    @Resource
    private RedisTemplate<String, WeChatSessionResponse> redisTemplate;

    @Resource
    private WeChatLoginSupport weChatLoginSupport;

    @Resource
    private GeneticTestingUserRepository geneticTestingUserRepository;

    @Resource
    private OperationAccountRepository operationAccountRepository;

    @Resource
    private VersionService versionService;

    @Value("${user.avatar.default}")
    private String userDefaultAvatar;

    @Value("${user.login.validation.flag}")
    private Boolean userLoginValidationFlag;

    /**
     * 根据id获取用户信息
     *
     * @param id 用户id
     * @return
     */
    @Override
    public ApiResult userById(String id) {
        String userNameInfo = null;
        GeneticTestingUserDto geneticTestingUser = managerRepository.geneticUserById(id);
        if (geneticTestingUser != null) {
            userNameInfo = geneticTestingUser.getRealName();
        }
        return new ApiResult(200, "success", "获取用户信息成功", userNameInfo);
    }

    /**
     * 普通用户短信登录处理
     *
     * @param loginInfo 登录信息
     * @return 登录结果
     */
    private ApiResult<GeneticTestingUserDto> smsCodeLogin(UserLoginInfoDto loginInfo) {
        // 校验登录短信验证码
        if (userLoginValidationFlag && !checkLoginVerifyCode(loginInfo.getUserName(), loginInfo.getSmsCode())) {
            return ApiResult.fail(UserErrorCode.LOGIN_VERIFY_CODE_ERROR);
        }
        GeneticTestingUser user = geneticTestingUserRepository.findByPhone(loginInfo.getUserName());
        if (user == null) {
            // 该手机号未注册
            ApiResult<GeneticTestingUser> registerResult = registerCustomer(loginInfo);
            if (!registerResult.isSucc()) {
                return ApiResult.fail(registerResult.getError());
            }
            user = registerResult.getData();
        }
        return ApiResult.succ(UserConverter.toGeneticTestingUserDto(user));
    }

    /**
     * 普通用户密码登录处理
     *
     * @param loginInfo 登录信息
     * @return 登录结果
     */
    private ApiResult<GeneticTestingUserDto> passwordLogin(UserLoginInfoDto loginInfo) {
        GeneticTestingUser user = geneticTestingUserRepository.findByPhone(loginInfo.getUserName());
        if (user == null) {
            return ApiResult.fail(UserErrorCode.USER_NAME_OR_PASSWORD);
        }
        if (userLoginValidationFlag) {
            ErrorCode errorCode = checkPassword(loginInfo.getPassword(), true, user.getPassword());
            if (errorCode != null) {
                return ApiResult.fail(errorCode);
            }
        }

        return ApiResult.succ(UserConverter.toGeneticTestingUserDto(user));
    }

    /**
     * 运营后台登录处理
     *
     * @param loginInfo 登录信息
     * @return 登录结果
     */
    private ApiResult<GeneticTestingUserDto> managerLogin(UserLoginInfoDto loginInfo) {
        GeneticTestingOperationAccount operationAccount = operationAccountRepository.findByName(loginInfo.getUserName());
        if (operationAccount == null || operationAccount.getDeleteFlag() == 1) {
            return ApiResult.fail(UserErrorCode.USER_NOT_EXISTED);
        }
        if (userLoginValidationFlag) {
            ErrorCode errorCode = checkPassword(loginInfo.getPassword(), true, operationAccount.getPassword());
            if (errorCode != null) {
                return ApiResult.fail(errorCode);
            }
        }

        GeneticTestingUserDto user = UserConverter.toGeneticTestingUserDto(operationAccount);
        //判断用户最近一次登录是否早于最新版本的发布时间，如果是则需要在弹出一次最新的版本信息
        ApiResult<Pagination<VersionDto>> versionResult = versionService.versionPages(1, 1, null, null, "release_date_time", true);
        if(versionResult.isSucc()){
            Pagination<VersionDto> data = versionResult.getData();
            if(data!=null){
                VersionDto versionDto = data.getResult().get(0);
                Date releaseDateTime = versionDto.getReleaseDateTime();
                //如果发布时间小于当前时间
                if(releaseDateTime.getTime()<=System.currentTimeMillis()){
                    //判断用户在新版本是否是第一次登录
                    Date latestLoginDateTime = user.getExtra().getLatestLoginDateTime();
                    if(latestLoginDateTime.getTime()<releaseDateTime.getTime()){
                        user.setNewVersinFirstLogin(1);
                    }
                }
            }
        }
        // 当第一次用户登录时，强制用户修改密码
        if (operationAccount.getLatestLoginDateTime() == null) {
            user.getExtra().setFirstLogin(Boolean.TRUE);
            user.getExtra().setPwdInitToken(UUID32.randomUUIDString());
        } else {
            Date latestLoginDateTime = new Date();
            user.getExtra().setLatestLoginDateTime(latestLoginDateTime);
            operationAccountRepository.updateLatestLoginDateTime(operationAccount.getId(), latestLoginDateTime);
        }

        return ApiResult.succ(user);
    }

    @Override
    public ApiResult<GeneticTestingUserDto> login(UserLoginInfoDto loginInfo) {
        ErrorCode errorCode = loginInfo.check();
        if (errorCode != null) {
            return ApiResult.fail(errorCode);
        }
        if (CustomerSourceType.WEB_CONSOLE.equals(loginInfo.parseSourceType())) {
            // 运营管理人员登录
            return managerLogin(loginInfo);
        } else {
            if (UserLoginInfoDto.SMS_LOGIN.equals(loginInfo.getLoginType())) {
                // 通过短信验证码登录
                return smsCodeLogin(loginInfo);
            } else {
                // 通过密码登录
                return passwordLogin(loginInfo);
            }
        }
    }

    /**
     * 校验用户密码
     *
     * @param loginPassword 登录密码
     * @param needDecrypt   密码是否需要解密
     * @param password      用户实际密码
     * @return 校验结果
     */
    private ErrorCode checkPassword(String loginPassword, boolean needDecrypt, String password) {
        String decryptPassword;
        if (needDecrypt) {
            ApiResult<String> decryptResult = securityService.rsaDecrypt(loginPassword);
            if (!decryptResult.isSucc()) {
                return decryptResult.getError();
            }
            decryptPassword = decryptResult.getData();
        } else {
            decryptPassword = loginPassword;
        }
        if (!password.equals(MD5Utils.getMD5Code(decryptPassword))) {
            return UserErrorCode.USER_NAME_OR_PASSWORD;
        }
        return null;
    }

    /**
     * 注册用户信息
     *
     * @param loginInfo 登录信息
     * @return 注册结果
     */
    private ApiResult<GeneticTestingUser> registerCustomer(UserLoginInfoDto loginInfo) {
        RegisterDto registerInfo = new RegisterDto();
        registerInfo.setPhone(loginInfo.getUserName());
        // 注册用户信息
        return registerService.registerCustomer(registerInfo);
    }

    /**
     * 校验登录验证码是否正确
     *
     * @param phone   手机号号码
     * @param smsCode 登录短信验证码
     * @return 校验结果
     */
    private boolean checkLoginVerifyCode(String phone, String smsCode) {
        return smsService.checkLoginVerifyCode(phone, smsCode);
    }


    @Override
    public ApiResult<WeChatLoginResponseDto> wechatLogin(String code) {
        // 1、根据获取openid查询数据库是否是已经授权登录过的用户
        // PS：此处往后公司账号下有多个微信平台需要微信用户共享时，需要根据unionid来进行过查询
        // 1.1、登录过：更新用户session_key
        // 1.2、没有登录过：插入新用户数据
        WeChatSessionResponse response = weChatLoginSupport.getWechatUser(code);
        if (!response.isSuccess()) {
            LOGGER.error("用户微信登录失败：code = {}, errCode = {}, errmsg = {}", code, response.getErrcode(), response.getErrmsg());
            return ApiResult.fail(response.getErrorCode());
        }
        WeChatLoginResponseDto responseDto = new WeChatLoginResponseDto();
        GeneticTestingUser user = geneticTestingUserRepository.findByOpenId(response.getOpenid());
        if (user == null) {
            // 未绑定，缓存微信SessionResponse
            redisTemplate.opsForValue().set(WeChatSessionResponse.WECHAT_SESSION_RESPONSE_CACHE_KEY + response.getOpenid(), response);
            responseDto.setNeedBinding(true);
            responseDto.setBindingKey(response.getOpenid());
        } else {
            // 已绑定，更新用户信息
            user.setUnionId(response.getUnionid());
            user.setSessionKey(response.getSession_key());
            user.setUpdateDateTime(new Date());
            geneticTestingUserRepository.updateUser(user);

            responseDto.setNeedBinding(false);
            responseDto.setUser(UserConverter.toGeneticTestingUserDto(user));
        }

        return ApiResult.succ(responseDto);
    }

    @Override
    public ApiResult<GeneticTestingUserDto> wechatBinding(WeChatBindingRequestDto bindingRequest) {
        bindingRequest.check();
        // 绑定时获取缓存的微信SessionResponse
        WeChatSessionResponse cachedSessionResponse = redisTemplate.opsForValue().get(WeChatSessionResponse.WECHAT_SESSION_RESPONSE_CACHE_KEY + bindingRequest.getBindingKey());
        if (cachedSessionResponse == null) {
            return ApiResult.fail(UserErrorCode.WECHAT_RELATION_INFO_NOT_EXISTED);
        }
        // 根据session_key和iv解密密文电话号码
        String decryptPhone = weChatLoginSupport.decrypt(cachedSessionResponse, bindingRequest.getPhone(), bindingRequest.getIv());
        if (decryptPhone == null) {
            LOGGER.error("解密失败：session_key过期");
            return ApiResult.fail(UserErrorCode.WECHAT_SESSION_KEY_EXPIRED);
        }
        // 新建或更新用户信息
        bindingRequest.setPhone(decryptPhone);
        GeneticTestingUser user = geneticTestingUserRepository.findByPhone(decryptPhone);
        if (user == null) {
            user = buildGeneticTestingUser(bindingRequest, cachedSessionResponse);
            geneticTestingUserRepository.saveUser(user);
        } else {
            user.setAvatar(bindingRequest.getAvatar());
            user.setUpdateDateTime(new Date());
            user.setOpenId(cachedSessionResponse.getOpenid());
            user.setSessionKey(cachedSessionResponse.getSession_key());
            user.setUnionId(cachedSessionResponse.getUnionid());
            geneticTestingUserRepository.updateUser(user);
        }
        return ApiResult.succ(UserConverter.toGeneticTestingUserDto(user));
    }

    private GeneticTestingUser buildGeneticTestingUser(WeChatBindingRequestDto bindingRequest, WeChatSessionResponse cachedSessionResponse) {
        GeneticTestingUser user = new GeneticTestingUser();
        user.setId(UUID32.randomUUIDString());
        user.setNick(bindingRequest.getNick());
        user.setName(bindingRequest.getPhone());
        user.setPhone(bindingRequest.getPhone());
        user.setAvatar(bindingRequest.getAvatar());
        user.setUserType(UserIntType.CUSTOMER.getValue());
        user.setCreateDateTime(new Date());
        user.setGender(bindingRequest.getGender());
        user.setDefaultAvatar(userDefaultAvatar);
        user.setOpenId(cachedSessionResponse.getOpenid());
        user.setSessionKey(cachedSessionResponse.getSession_key());
        user.setUnionId(cachedSessionResponse.getUnionid());
        return user;
    }
}
